<?php

namespace System\Types;

require_once __DIR__ . '/IObject.php';

class Object implements IObject
{

    private static $_codeIncrement = 0;
    private $_code = 0;
    protected $_disposed;

    function __construct()
    {
        $this->_code = self::$_codeIncrement;
        self::$_codeIncrement++;
    }

    /**
     * @return string
     */
    public static function GetTheName()
    {
        return \get_called_class();
    }

    public static function GetNamespace()
    {
        $ref = new \ReflectionClass(\get_called_class());

        $namespace = $ref->getNamespaceName();

        $namespace = $namespace[0] !== '\\' ? ('\\' . $namespace) : $namespace;

        return $namespace;
    }

    /**
     * Compare if the item is equal to the same object.
     *
     * @param Object $obj
     * @return bool
     */
    public function Equal(Object $obj)
    {
        if (\is_null($obj) || $this->GetType() != $obj->GetType())
            return false;

        return $obj === $this ? ($this->GetHashCode() === $obj->GetHashCode()) : false;
    }

    /**
     * Compare if the items are equal.
     *
     * @param Object $obj
     * @param Object $obj2
     * @return bool
     */
    public static function Equals(Object $obj, Object $obj2)
    {
        return ((!\is_null($obj) && $obj->Equal($obj2)) || (\is_null($obj) && \is_null($obj2)));
    }

    /**
     * Generates a unique code for the current object.
     *
     * @return integer
     */
    public function GetHashCode()
    {
        $code = \spl_object_hash($this);

        return \hexdec($code);
    }

    /**
     * Returns the current object's type.
     *
     * @return \ReflectionClass
     */
    public function GetType()
    {
        return Type::TypeOf($this);
    }

    /**
     * @return string
     */
    public function ToString()
    {
        return self::GetTheName();
    }

    /**
     * @access private
     * @return string
     */
    public final function __toString()
    {
        return $this->ToString();
    }

    /**
     * Perform a shallow copy of the current object.
     *
     * @return Object
     */
    public function MemberwiseClone()
    {
        return clone $this;
    }

    /**
     * @access private
     *
     * @return Object
     */
    public final function __clone()
    {
        return $this->MemberwiseClone();
    }

    /**
     * Determines whether the specified Object instances are the same instance.
     *
     * @param Object $obj
     * @param Object $obj2
     * @return bool
     */
    public static function ReferenceEquals(Object $obj, Object $obj2)
    {
        if (\is_null($obj) && \is_null($obj2) || self::Equals($obj, $obj2))
            return true;

        if (\is_null($obj) || \is_null($obj2))
            return false;

        $t1 = $obj->GetType();

        $t2 = $obj2->GetType();

        /* @var $irefs1 \ReflectionClass */
        $irefs1 = $t1->getInterfaces();

        /* @var $irefs1 \ReflectionException */
        $arefs1 = $t1->getExtension();

        /* @var $irefs2 \ReflectionClass */
        $irefs2 = $t2->getInterfaces();

        /* @var $irefs2 \ReflectionException */
        $arefs2 = $t2->getExtension();

        $arefs = false;

        if (\is_null($arefs1) && \is_null($arefs2))
            $arefs = true;

        $irefs = false;

        if (\count($irefs1) === \count($irefs2))
            $irefs = true;

        if ($irefs)
        {
            $r = false;

            for ($i = 0; $i < \count($irefs1); $i++)
            {
                $eq = false;

                for ($j = 0; $j < \count($irefs2); $j++)
                {
                    if ($irefs2[$j]->getName() === $irefs1[$i]->getName()
                            && $irefs2[$j]->getNamespaceName() === $irefs1[$i]->getNamespaceName()
                            && $irefs2[$j]->getFileName() === $irefs1[$i]->getFileName())
                    {
                        $eq = true;
                        break;
                    }
                }

                $r = $eq;

                if (!$eq)
                    break;
            }

            if (!$r)
                return false;

            $irefs = true;
        }

        return ($arefs === true && $irefs === true);
    }

    public static function &GetInstance()
    {
        $obj = new Object();
        return $obj;
    }

    public function Dispose()
    {
        if ($this->_disposed)
            return $this->_disposed;

        $this->_disposed = true;

        return false;
    }

    public function __destruct()
    {
        if (!$this->_disposed)
            $this->Dispose();
    }

}

require_once __DIR__ . \DIRECTORY_SEPARATOR . 'Reflections' . \DIRECTORY_SEPARATOR . 'ReflectionAssembly.php';
require_once __DIR__ . \DIRECTORY_SEPARATOR . 'Type.php';
